Ga naar hoofdinhoud

Classes

Functioneel en Objectgeoriënteerd Programmeren in JavaScript

JavaScript is een veelzijdige programmeertaal die zowel functioneel als objectgeoriënteerd programmeren ondersteunt.

Functioneel programmeren

Functioneel programmeren is een programmeringsparadigma dat functies als de belangrijkste bouwstenen gebruikt. Het richt zich op het toepassen van functies en immutabiliteit, en vermijdt het gebruik van toestandsverandering en bijwerkingen. Belangrijke concepten van functioneel programmeren zijn onder andere:

  • Hogere-orde functies: Functies die andere functies als argumenten accepteren of functies retourneren.
  • Immutabiliteit: Het idee dat eenmaal gemaakte gegevens niet kunnen worden veranderd, wat leidt tot meer voorspelbare code.
  • Functies als eerste-klas burgers: Functies kunnen worden opgeslagen in variabelen, als argumenten worden doorgegeven en als waarden worden geretourneerd.

Objectgeoriënteerd Programmeren (OOP)

Objectgeoriënteerd programmeren (OOP) is een paradigma dat gebruik maakt van "objecten" om gegevens en functies te organiseren. In JavaScript wordt OOP voornamelijk bereikt via klassen, die het mogelijk maken om objecten te creëren met een bepaalde structuur en functionaliteit.

Classes

Classes zijn blauwdrukken voor het creëren van objecten. Ze definiëren de structuur (attributen) en functionaliteit (methoden) van de objecten die ervan worden gemaakt. Dit maakt het gemakkelijk om meerdere objecten te creëren die dezelfde eigenschappen en methoden delen.

class Persoon {
constructor(naam, leeftijd) {
this.naam = naam;
this.leeftijd = leeftijd;
}

zegHallo() {
console.log(`Hallo, mijn naam is ${this.naam} en ik ben ${this.leeftijd} jaar oud.`);
}
}

const persoon1 = new Persoon('Alice', 30);
persoon1.zegHallo(); // Output: Hallo, mijn naam is Alice en ik ben 30 jaar oud.

Constructor Functie

De constructorfunctie is een speciale methode binnen een klasse die wordt aangeroepen wanneer een nieuw object wordt gemaakt. Het is verantwoordelijk voor het initialiseren van de eigenschappen van het object. Met de new-operator kan een nieuw object worden aangemaakt en de constructor wordt automatisch aangeroepen.

Overerving

Overerving of inheritance stelt een klasse in staat om eigenschappen en methoden van een andere klasse over te nemen. Dit bevordert de herbruikbaarheid van code en maakt het gemakkelijker om een hiërarchie van klassen te creëren. Subklassen kunnen de functionaliteit van hun superklassen uitbreiden of aanpassen.

class Werknemer extends Persoon {
constructor(naam, leeftijd, functie) {
super(naam, leeftijd); // Aanroepen van de constructor van de bovenliggende klasse
this.functie = functie;
}

zegHallo() {
console.log(`Hallo, ik ben ${this.naam}, een ${this.functie}.`);
}
}

const werknemer1 = new Werknemer('Bob', 28, 'ontwikkelaar');
werknemer1.zegHallo(); // Output: Hallo, ik ben Bob, een ontwikkelaar.

Encapsulatie

Encapsulatie is het principe waarbij je de interne staat van een object kunt verbergen en alleen via methoden toegang verleent. Dit helpt om een duidelijke interface te definiëren en voorkomt dat de interne staat van een object per ongeluk wordt gewijzigd. In JavaScript wordt dit vaak bereikt met getters en setters, of door het gebruik van hashtag (#) voor privé-eigenschappen.

class Bankrekening {
constructor(eigenaar, saldo) {
this.eigenaar = eigenaar;
this.#saldo = saldo;
}

stort(bedrag) {
this.#saldo += bedrag;
}

haalOp(bedrag) {
if (this.#saldo >= bedrag) {
this.#saldo -= bedrag;
} else {
console.log('Niet genoeg saldo.');
}
}

get saldo() {
return this.#saldo; // Getter voor saldo
}
}

const rekening = new Bankrekening('Charles', 1000);
rekening.stort(500);
console.log(rekening.saldo); // Output: 1500
rekening.haalOp(2000); // Output: Niet genoeg saldo.

Polymorfisme

Polymorfisme verwijst naar de mogelijkheid dat verschillende klassen dezelfde methoden kunnen implementeren, met mogelijk verschillende implementaties. Dit maakt het mogelijk om op een uniforme manier met objecten van verschillende klassen om te gaan. Het biedt de flexibiliteit om objecten te gebruiken zonder de exacte klasse te kennen.

class Dier {
geluid() {
console.log('Dit dier maakt een geluid.');
}
}

class Hond extends Dier {
geluid() {
console.log('Woef!');
}
}

class Kat extends Dier {
geluid() {
console.log('Miauw!');
}
}

const dieren = [new Hond(), new Kat()];
dieren.forEach(dier => dier.geluid());
// Output:
// Woef!
// Miauw!

Static

Statische methoden zijn functies die behoren tot de klasse zelf en niet tot een instantie van de klasse. Dit betekent dat ze kunnen worden aangeroepen zonder een object van die klasse te maken. Statische methoden zijn handig voor functionaliteiten die niet afhankelijk zijn van de instance van de klasse, zoals hulpfuncties, fabrieksmethoden of algemene utilities.

Belangrijk om te weten over static methodes
  1. Geen Toegang tot Instantie-Eigenschappen: Statische methoden kunnen geen toegang krijgen tot this, omdat ze niet worden aangeroepen op een specifieke instantie van de klasse. Ze zijn alleen toegankelijk via de klasse zelf.

  2. Aanroep via de Klasse: Statische methoden worden aangeroepen via de klasse, niet via een instantie. Dit maakt het duidelijk dat de methode niet afhankelijk is van een specifiek object.

  3. Gebruik voor Hulpfuncties: Ze zijn ideaal voor functies die gerelateerd zijn aan de klasse maar niet afhankelijk zijn van de status van een specifiek object. Dit kan nuttig zijn voor validatie, berekeningen of het maken van nieuwe instanties.

Stel je voor dat we een klasse Bankrekening hebben en we willen een statische methode toevoegen die het maximale bedrag voor een storting controleert. We kunnen dit als volgt doen:

class Bankrekening {
constructor(eigenaar, saldo) {
this.eigenaar = eigenaar;
this.#saldo = saldo; // Privé-eigenschap
}

// Statische methode om het maximale bedrag te controleren
static controleerMaximaleStorting(bedrag) {
const MAXIMUM = 10000;
return bedrag <= MAXIMUM;
}

stort(bedrag) {
// BELANGRIJK! Je roept een statische methode op op de class, niet een instantie ervan.
if (Bankrekening.controleerMaximaleStorting(bedrag)) {
this.#saldo += bedrag; // Toegang tot privé-eigenschap
} else {
console.log('Het bedrag overschrijdt het maximale stortingslimiet.');
}
}

haalOp(bedrag) {
if (this.#saldo >= bedrag) {
this.#saldo -= bedrag; // Toegang tot privé-eigenschap
} else {
console.log('Niet genoeg saldo.');
}
}

get saldo() {
return this.#saldo; // Getter voor saldo
}
}

const rekening = new Bankrekening('Charles', 1000);

rekening.stort(500); // Valide storting
console.log(rekening.saldo); // Output: 1500

rekening.stort(12000); // Onvalide storting, overschrijdt het maximum
console.log(rekening.saldo); // Output: 1500

In het bovenstaande voorbeeld wordt de statische methode controleerMaximaleStorting gebruikt om te controleren of een storting binnen het maximum valt. Dit laat zien hoe statische methoden nuttig kunnen zijn om logica te implementeren die relevant is voor de klasse als geheel.

Oefeningen

Deel 1

  • Schrijf een klasse Spel met volgende eigenschappen (properties)
    • prijs
    • naam
    • omschrijving
    • aantal in stock

en volgende methodes:

  • printSpelregels -> print de spelregels van je spel
  • afrekenen -> geeft de prijs van het spel terug
  • stockAanvullen -> verhoogd de hoeveelheid in stock met 100

Deel 2

Spel heeft een subklasse VideoSpel.VideoSpel heeft als extra eigenschappen

  • console waar het op gespeeld kan worden (XBox, PlayStation, Computer)
  • of het spel in cheatMode staat. CheatMode is een privé property.
  • een maximum aantal levels (wanneer het spel uitgespeeld is)
  • een huidig level. Als extra methode heeft een VideoSpel
  • een levelUp methode. Deze methode aanroepen zorgt ervoor dat het huidige level met 1 wordt verhoogd. Het huidige level kan niet hoger zijn dan de maximum aantal levels.
  • een spelUitgespeeld methode. Als cheatmode aanstaat geeft dit altijd true terug. Anders checkt het of het huidige level gelijk is aan het maximum aantal levels.
  • zijn eigen methode van afrekenen. Deze methode gaat teruggeven dat de prijs betaald is via het internet.

Deel 3

Spel heeft een subklasse GezelschapSpel . GezelschapSpel heeft als extra eigenschappen

  • een lijst (array) van onderdelen (mag om het simpel te houden een lijst van strings zijn)
  • een minimumleeftijd
  • een maximumleeftijd

Als extra methode heeft een GezelschapSpel:

  • een printOnderdelen methode. Deze print een lijst van de onderdelen in het spel af.
  • een bestelExtraOnderdelen methode. Bestel extra onderdelen voegt een onderdeel toe (bijvoorbeeld een kaartuitbreiding) aan de lijst van onderdelen.
  • een geschiktVoorMij methode. Deze methode heeft als input een leeftijd en zegt of je de juiste leeftijd hebt voor het spel.